#include "Clock_Interrupt_Handler.h"
#include "interrupt.h"
#include "thread.h"
#include "debug.h"
#include "virtual_pit8253.h"
#include "virtual_pic8259a.h"
#include "vmm.h"
#include "keyboard.h"
#include "scan_patch.h"

/* 时钟的中断处理函数 */
void intr_timer_handler(void) {
   struct task_struct* cur_thread = running_thread();
   uint32_t guest_tss;
   uint32_t* esp;
   struct intr_stack* intr_stack;
   intr_stack = (struct intr_stack*)((*((uint32_t*)(0xc0000b0f))) - sizeof(struct intr_stack));


   ASSERT(cur_thread->stack_magic == 0x19870916);         // 检查栈是否溢出

   cur_thread->elapsed_ticks++;	  // 记录此线程占用的cpu时间嘀
   //ticks++;	  //从内核第一次处理时间中断后开始至今的滴哒数,内核态和用户态总共的嘀哒数

   if (cur_thread->ticks == 0) {	  // 若进程时间片用完就开始调度新的进程上cpu
      schedule(); 
   } 
   else {				  // 将当前进程的时间片-1
      cur_thread->ticks--;
   }
   
   cur_thread = running_thread();

   if (cur_thread->guest_ptr) {

      ((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pit_frequency_proportion++;
      
      if (((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pit_frequency_proportion == 5) {
         
         ((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pit_frequency_proportion = 0;
         if (!(IS_BIT_SET(((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->imr, 0))) {
            
            ((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->irr |= (1 << 0);
         }
      };

      if ((((int32_t)(guest_kbd_buf.head)) - ((int32_t)(guest_kbd_buf.tail))) != 0) {
         // put_int(guest_kbd_buf.head);
         // put_str("\n");
         // put_int(guest_kbd_buf.tail);
         // put_str("\n");
         // put_str("guest keyboard \n");
         //asm("jmp .");
         if (!(IS_BIT_SET(((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->imr, 1))) {
            ((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->irr |= (1 << 1);
         }
      } else {
         ((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->irr &= ~(1 << 1);
      }

      if(((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->eflags & (((uint32_t)1) << 9)) {
         if (((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->irr > 0) {

            int pic_pr_result = PIC_PR(((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic);

            CLEAR_BIT(((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic,pic_pr_result);
            ((struct PIC8259A*)((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->pic)->isr |= (1 << pic_pr_result);

            *((uint32_t*)(&(((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->eflags))) &= ~(1 << 9);

            if (pic_pr_result == 2) {
               pic_pr_result = 0xe;
            }

            *((uint32_t*)((uint32_t)(intr_stack->esp) - (uint32_t)4)) = intr_stack->eflags;
            *((uint32_t*)((uint32_t)(intr_stack->esp) - (uint32_t)8)) = (uint32_t)((struct gate_desc*)((((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->idtr_base + 0x0) + (8 * (0x20 + pic_pr_result))))->selector;
            *((uint32_t*)((uint32_t)(intr_stack->esp) - (uint32_t)12)) = (uint32_t)intr_stack->eip ;
            
            intr_stack->ss = 0x33;
            intr_stack->esp = (void*)((uint32_t)(intr_stack->esp) - (uint32_t)12);

            intr_stack->cs = 0x2b;
            
            intr_stack->eip = (void*)(0x00000000 +  ((struct gate_desc*)((((struct vcpu*)((struct task_struct*)cur_thread)->guest_ptr)->idtr_base + 0x0) + (8 * (0x20 + pic_pr_result))))->func_offset_low_word);
            
            // put_int(intr_stack->eip);
            // put_str("\n");
            //asm("jmp .");
            
            if (intr_stack->eip == 0x2301) {
               // put_int(intr_stack->eip);
               // put_str("\n");
               //asm("jmp .");
               x86_scan((void *)intr_stack->eip);
               //asm("jmp .");
            } else if (intr_stack->eip == 0x22eb) {
               // put_int(intr_stack->eip);
               // put_str("\n");
               x86_scan((void *)intr_stack->eip);
               //asm("jmp .");
            } else {
               put_str("guest interrupt\n");
               asm("jmp .");
            }

         }
      }
   }

}

